package com.chushouya.manager.service.admin.impl;

import cn.hutool.core.util.RandomUtil;
import com.chushouya.manager.dto.admin.bonustype.*;
import com.general.framework.core.enums.DelFlagEnum;
import com.general.framework.core.exception.Ex;
import com.general.framework.core.lang.*;
import com.general.framework.core.schema.PageRequest;
import com.general.framework.core.schema.PageResult;
import com.general.framework.web.utils.ExcelUtil;
import com.chushouya.manager.dao.entity.BonusTypeEntity;
import com.chushouya.manager.dao.entity.BonusUserEntity;
import com.chushouya.manager.dao.repository.BonusTypeRepository;
import com.chushouya.manager.dao.repository.BonusUserRepository;
import com.chushouya.manager.dto.admin.bonus.BonusNoExportDTO;
import com.chushouya.manager.dto.admin.bonus.BonusQuery;
import com.chushouya.manager.dto.admin.bonus.PreviewGrantBonusDTO;
//=====manager.dto.admin.bonustype.*;
import com.chushouya.manager.dto.admin.bonustype.*;
import com.chushouya.manager.service.admin.BonusTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Service
@Slf4j
public class BonusTypeServiceImpl implements BonusTypeService {

    @Resource
    private BonusTypeRepository bonusTypeRepository;

    @Resource
    private BonusUserRepository userBonusRepository;


    @Override
    public void save(BonusTypeSaveDTO dto) {
        Validate.isTrue(dto.getUseDay() == null && (dto.getStartTime() == null || dto.getEndTime() == null), "使用日期和有效期不能同时为空");
        BonusTypeEntity entity = Beans.copy(dto, BonusTypeEntity.class);
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());
        bonusTypeRepository.insertSelective(entity);
    }

    @Override
    public PageResult<BonusTypeListDTO> selectPage(BonusTypeQuery query) {
        PageResult<BonusTypeEntity> result = bonusTypeRepository.selectPage(query);
        return PageResult.of(result, BonusTypeListDTO.class);
    }

    @Override
    public BonusTypeDetailDTO detail(Long id) {
        BonusTypeEntity entity = selectByPrimaryKey(id);
        return Beans.copy(entity, BonusTypeDetailDTO.class);
    }

    @Override
    public void update(BonusTypeUpdateDTO dto) {
        Validate.isTrue(dto.getUseDay() == null && (dto.getStartTime() == null || dto.getEndTime() == null), "使用日期和有效期不能同时为空");
        BonusTypeEntity entity = selectByPrimaryKey(dto.getTypeId());
        Beans.copyProperties(dto, entity);
        bonusTypeRepository.updateByPrimaryKey(entity);
    }

    @Override
    public void remove(Long typeId) {
        log.info("删除红包类型: {}", typeId);
//        Validate.isTrue(userBonusRepository.existsWithBonusTypeId(typeId), "当前红包类型存在红包券，无法删除");
        BonusTypeEntity entity = new BonusTypeEntity();
        entity.setTypeId(typeId);
        entity.setDelFlag(DelFlagEnum.delete.getValue());
        bonusTypeRepository.updateByPrimaryKeySelective(entity);
    }

    @Override
    @Transactional
    public void previewGrantBonus(PreviewGrantBonusDTO dto) {
        Long bonusTypeId = dto.getTypeId();
        Integer quantity = dto.getQuantity();
        if (quantity == null || quantity < 1) {
            throw Ex.violation("发放数量参数异常, 至少发放1个红包");
        }
        if (quantity > 10000) {
            throw Ex.violation("发放数量参数异常, 一次最多发放10000个红包");
        }
        BonusTypeEntity bonusType = selectByPrimaryKey(bonusTypeId);
        //批量生成, 每1000条保存
        Date now = new Date();
        List<BonusUserEntity> userBonusEntityList = new ArrayList<>(1000);
        for (int i = 1; i <= quantity; i++) {
            BonusUserEntity userBonus = Beans.copy(bonusType, BonusUserEntity.class);
            final Date nowTime = Dates.getTimeNow();
            userBonus.setUserId(null);
            userBonus.setTypeId(bonusTypeId);
            userBonus.setCreateTime(now);
            userBonus.setEndTime(null);
            userBonus.setOrderId(Numbers.LONG_ZERO);
            userBonus.setCreateTime(nowTime);
            userBonus.setUpdateTime(nowTime);
            userBonus.setTicketNo(RandomUtil.randomStringUpper(10));
            log.info("生成红包券: {}, {} {}", userBonus.getTicketNo(), userBonus);
            userBonusEntityList.add(userBonus);
            if (userBonusEntityList.size() == 1000) {
                userBonusRepository.insertList(userBonusEntityList);
                userBonusEntityList.clear();
            }
        }
        if (userBonusEntityList.size() > 0) {
            userBonusRepository.insertList(userBonusEntityList);
        }
        bonusTypeRepository.updateSendNumber(bonusTypeId, quantity);
    }

    @Override
    public void exportNotReceiveTicketNo(HttpServletResponse response, Long typeId) {
        Validate.isNull(typeId, "红包类型不存在");
        BonusQuery query = new BonusQuery();
        query.setTypeId(typeId);
        query.setSize(100000);
        query.setPage(1);
        try {
            List<BonusUserEntity> userBonusEntities = userBonusRepository.selectList(query);
            List<BonusNoExportDTO> userBonusExportList = Beans.copyList(userBonusEntities, BonusNoExportDTO.class);
            log.info("导出红包券码数量: {}", userBonusExportList);
            String fileName = Strings.format("红包数据导出-{}", Dates.dateTimeNow());
            new ExcelUtil<>(BonusNoExportDTO.class).exportExcel(response, userBonusExportList, fileName, "红包数据");
        } catch (Exception e) {
            log.error("红包数据,{}", e.getMessage());
            throw Ex.systemError("红包数据");
        }
    }

    @Override
    @Transactional
    public void cashTicket(String ticketNo, Long userId) {
        BonusUserEntity userBonus = userBonusRepository.selectFirstByTicketNo(ticketNo);
        Validate.isNull(userBonus, "券码不存在");
        Validate.isTrue(userBonus.getUserId() != null, "券码失效");
        //兑换加价券
        BonusUserEntity update = new BonusUserEntity();
        update.setBonusId(userBonus.getBonusId());
        update.setUserId(userId);
        //计算加价券有效期
        BonusTypeEntity bonusType = bonusTypeRepository.selectByPrimaryKey(userBonus.getTypeId());
        Validate.isNull(bonusType, "优惠券不存在");
//        update.setEndTime(bonusType.computeEndTime());
        //更新
        userBonusRepository.updateByPrimaryKeySelective(update);
        //领取数量+1
        bonusTypeRepository.updateReceiveNumber(userBonus.getTypeId(), 1);
    }



    private BonusTypeEntity selectByPrimaryKey(Long id) {
        Validate.isNull(id, "id不存在");
        BonusTypeEntity entity = bonusTypeRepository.selectByPrimaryKey(id);
        Validate.isNull(entity, "红包不存在");
        return entity;
    }

    @Override
    public PageResult<BonusTypeTicketListDTO> ticketPage(Long bonusTypeId, PageRequest pageRequest) {
        Validate.isNull(bonusTypeId, "红包类型id不能为空");
        PageResult<BonusUserEntity> page = userBonusRepository.selectPageByBonusTypeId(bonusTypeId, pageRequest);
        return PageResult.of(page, BonusTypeTicketListDTO.class);
    }

    @Override
    @Transactional
    public void removeTickets(List<Long> ids) {

        if (Lists.isEmpty(ids)) {
            return;
        }

        List<BonusUserEntity> userBonusEntities = userBonusRepository.selectByPrimaryKeyList(ids);
        if (Lists.isEmpty(userBonusEntities)) {
            return;
        }

        //统计每个红包类型的领取数量和发送数量, 正常操作下删除的应该是同一个红包类型的红包券
        Map<Long, Integer> sendMap = new HashMap<>();
        Map<Long, Integer> receiveMap = new HashMap<>();
        for (BonusUserEntity userBonus : userBonusEntities) {
            Long bonusTypeId = userBonus.getTypeId();
            sendMap.compute(bonusTypeId, (k, v) -> v == null ? -1 : v - 1);
            if (userBonus.getUserId() != null) {
                receiveMap.compute(bonusTypeId, (k, v) -> v == null ? -1 : v - 1);
            }
        }

        //更新红包类型发送数量
        sendMap.forEach(bonusTypeRepository::updateSendNumber);
        //更新红包类型领取数量
        receiveMap.forEach(bonusTypeRepository::updateReceiveNumber);
        //删除红包券
        userBonusRepository.deleteByIdList(ids);
    }

}
